/**
 * 文件名:  socket_utils.h
 * 作者:    wangtianliang
 * 日期:    2022-10-20
 * 功能:   
 * 	socket相关处理封装库
 */

#ifndef _SOCK_UTILS_H_
#define _SOCK_UTILS_H_

#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h> 
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h> 
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h> 
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define FAILURE 1
#define SUCCESS 0

#define SOCKET_PORT_MAX     65536       /* 端口号最大值 */
#define STR_PORT_MAX        8           /* 端口号字符串最大长度 */

//地址结构体
typedef struct sockaddr  sa_st;

/**
 * it returns file descriptor for the socket
 * \param [in]	family 
 * \param [in]	type 
 * \param [in]	protocol 
 * \return	int    success, return socket fd; fail, return < 0
 */
int socket_open (int family, int type, int protocol);

/**
 * it assigns a local address to a socket
 * \param [in]	socket 
 * \param [in]	address 
 * \param [in]	addrlen 
 * \return	int     success, return 0; fail, return != 0
 */
int socket_bind (int sockfd, const sa_st *myaddr, socklen_t myaddrlen);

/**
 * set a socket in passive mode, in order to listen to a connection
 * \param [in]	socket 
 * \param [in]	backlog 
 * \return	int success, return 0; fail, return -1
 */
int socket_listen (int sockfd, int backlog);

/**
 * it manages a new connection after the end of three-way handshake
 * \param [in]	socket 
 * \param [in]	clientAddr 
 * \param [in]	addrlen 
 * \return	int    success, return accept socket fd; fail, return -1
 */
int socket_accept (int listen_sockfd, sa_st *cliaddr, socklen_t *addrlenp);

/**
 * it establishes a new connection with a server
 * \param [in]	socket 
 * \param [in]	serverAddress 
 * \param [in]	addrlen 
 * \return	int     success, return 0; fail, return -1
 */
int socket_connect (int sockfd, const sa_st *srvaddr, socklen_t addrlen);

/**
 * set a socket as closed
 * \param [in|out]	socket 
 * \return	int     success, return 0; fail, return -1
 */
int socket_close(int fd);

/**
 * SELECT
 * \param [in]	maxfdp1 
 * \param [in]	readset 
 * \param [in]	writeset 
 * \param [in]	exceptset 
 * \param [in]	timeout 
 * \return	int success, return != -1; fail, return -1
 */
int my_select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,struct timeval *timeout);

/**
 * it tries to read from the socket
 * \param [in]	socket 
 * \param [in]	buffer 
 * \param [in]	len 
 * \param [in]	flag 
 * \return	int     success, return recv byte; fail, return -1; peer close, return 0;
 */
int socket_recv(int socket,void *buffer,int len,int flag);

/**
 * it tries to send data to the socket
 * \param [in]	socket 
 * \param [in]	buffer 
 * \param [in]	len 
 * \param [in]	flags 
 * \param [in]	epipeError 
 * \return	int     success, return send byte; fail, return -1;
 */
int socket_send(int socket,void *buffer,int len, int flags, int *epipeError);

/**
 * inet_pton
 * \param [in]	af 
 * \param [in]	strptr 
 * \param [in]	addrptr 
 */
int my_inet_pton(int af, const char *strptr, void *addrptr);

/**
 * inet_ntop 
 * \param [in]	af 
 * \param [in]	addrptr 
 * \param [in]	strptr 
 * \param [in]	length 
 * \return	const char* 
 */
const char *my_inet_ntop(int af, const void *addrptr, char *strptr, size_t length);

/**
 * 设置socket addr
 * \param [in]	psock 
 * \param [in]	addr 
 * \param [in]	port 
 * \return	int success:0, failed:-1
 */
int socket_addr_set(struct sockaddr_in *psock, char *addr, int port);

/**
 * 将字符串类型的ip地址和端口，格式化成sddrinfo结构
 * \param [in]	pres 存放格式化的结果
 * \param [in]	ip 这里的ip支持 ipv4 ipv6 域名等格式
 * \param [in]	port 端口字符串
 * \return	int     success, return 0; fail, return -1;
 */
int socket_addrinfo_get(struct addrinfo **pres, char *ip, char *port);

/**
 * 关闭addrinfo结构
 * \param [in]	res 
 */
void socket_addrinfo_free(struct addrinfo *res);

#endif
